use crate::config::app_list::app_config::AppConfig;
use crate::config::app_list::site_config::SiteConfig;


#[derive(Debug, Clone)]
pub struct AppWithSiteConfig {
  pub app_config: AppConfig,
  pub site_config: SiteConfig,
}

impl AppWithSiteConfig {
  pub fn new(app_config: AppConfig, site_config: SiteConfig) -> Self {
    Self {
      app_config,
      site_config,
    }
  }

  pub fn get_app_name(&self) -> &str {
    self.app_config.app_name.as_str()
  }

  pub fn get_site_name(&self) -> &str {
    self.site_config.get_site_name()
  }

  pub fn get_union_name(&self) -> String {
    format!("{}.{}", self.site_config.get_site_name(), self.app_config.app_name)
  }

  pub fn get_app_yml_path(&self) -> String {
    let site_directory = self.site_config.get_site_directory();
    let app_name = self.app_config.app_name.as_str();
    format!("{}/apps/{}.yml", site_directory, app_name)
  }

  pub fn get_app_cache_log_yml_path(&self) -> String {
    let cache_site_dir = self.site_config.site_base.get_cache_site_directory();
    let app_name = self.app_config.app_name.as_str();
    format!("{}/apps/{}.yml", cache_site_dir, app_name)
  }

  pub fn get_app_url_prefix(&self) -> String {
    let mut site_origin = self.site_config.get_url_origin();
    if site_origin.ends_with("/") {
      site_origin = &site_origin[..site_origin.len() - 1];
    }
    let app_name = self.app_config.get_url_prefix();
    if app_name.starts_with("/") {
      return format!("{}{}", site_origin, app_name);
    }
    format!("{}/{}", site_origin, app_name)
  }

  pub fn get_app_url_index(&self) -> String {
    let app_url_prefix = self.get_app_url_prefix();
    format!("{}/index.html", app_url_prefix)
  }

  pub fn get_app_url_version(&self) -> String {
    let app_url_prefix = self.get_app_url_prefix();
    format!("{}/version.json", app_url_prefix)
  }
}

pub fn find_target_app_by<'a>(
  config_vec: &'a Vec<AppWithSiteConfig>,
  name: &str,
) -> Option<&'a AppWithSiteConfig> {
  if name.contains(".") {
    let result = config_vec.iter().find(|app_with_site_config| {
      app_with_site_config.get_union_name().eq(name)
    });
    return result;
  }
  config_vec.iter().find(|app_with_site_config| {
    app_with_site_config.get_app_name().eq(name)
  })
}

pub fn find_target_app_vec_by(
  name_list: &Vec<String>,
  config_vec: &Vec<AppWithSiteConfig>,
) -> Vec<AppWithSiteConfig> {
  if name_list.is_empty() {
    return config_vec.clone();
  }
  let mut result_vec = Vec::new();
  let mut wrong_name_vec: Vec<&str> = Vec::new();
  for name in name_list {
    let result = find_target_app_by(config_vec, name.as_str());
    if result.is_some() {
      let target_config = result.unwrap().clone();
      result_vec.push(target_config);
    } else {
      wrong_name_vec.push(name.as_str());
    }
  }
  if !wrong_name_vec.is_empty() {
    panic!("cannot found name {:#?}", wrong_name_vec);
  } 
  return result_vec;
}

static APP_WITH_SITE_CONFIG_VEC: once_cell::sync::OnceCell::<Vec<AppWithSiteConfig>> = once_cell::sync::OnceCell::new();

pub fn init_app_with_site_config_vec(target_vec: Vec<AppWithSiteConfig>) {
  APP_WITH_SITE_CONFIG_VEC.set(target_vec).expect("set APP_WITH_SITE_CONFIG_VEC error");
}

pub fn get_app_with_site_config_vec() -> &'static Vec<AppWithSiteConfig> {
  APP_WITH_SITE_CONFIG_VEC.get().expect("get APP_WITH_SITE_CONFIG_VEC error")
}
